#include "expression.h"
#include "parse_history.h"
#include "type.h"
#include <map.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

exp_tree* exp_tree_create( vartype *ret, token *opt, void* opd1, void* opd2, void* opd3 )
{
    exp_tree *et = (exp_tree *)malloc( sizeof(exp_tree) );
    init_life( et );
    et->opt = opt;
    et->ret = ret;
    et->opd1 = opd1;
    et->opd2 = opd2;
    et->opd3 = opd3;
    switch( (long)opt )
    {
    case -2:    // expression for condition #ifndef
        add_ref( ret );
        add_ref( opd1 );
        break;
    case -1:    // expression for condition #ifdef
        add_ref( ret );
        add_ref( opd1 );
        break;
    case 0:     // primary expression: no operator
        add_ref( ret );
        add_ref( opd1 );
        break;
    default:
        add_ref( ret );
        add_ref( opt );
        if( PCT_TYPE(opt) == PCT_CALL )
        {
            int i;
            exp_tree **el = (exp_tree **)opd2;
            add_ref( opd1 );
            for( i = 0; i < (long)opd3; ++i )
                add_ref( el[i] );
        }
        else
        {
            if( opd1 )
                add_ref( opd1 );
            if( opd2 )
                add_ref( opd2 );
            if( opd3 )
                add_ref( opd3 );
        }
        break;
    }
    return et;
}

int exp_tree_release( exp_tree* et )
{
    int ref = 0;
    if( et )
    {
        ref = release( et );
        if( ref <= 0 )
        {
            switch( (long)et->opt )
            {
            case -2:    // expression for condition #ifndef
                vt_release( et->ret );
                token_release( (token *)et->opd1 );
                break;
            case -1:    // expression for condition #ifdef
                vt_release( et->ret );
                token_release( (token *)et->opd1 );
                break;
            case 0:     // primary expression: no operator
                vt_release( et->ret );
                token_release( (token *)et->opd1 );
                break;
            default:
                vt_release( et->ret );
                token_release( et->opt );
                if( PCT_TYPE(et->opt) == PCT_SIZEOF )
                {
                    if( et->opd2 )
                        exp_tree_release( (exp_tree *)et->opd1 );
                    else
                        vt_release( (vartype*)et->opd1 );
                }
                else if( PCT_TYPE(et->opt) == PCT_CALL )
                {
                    int i;
                    exp_tree **el = (exp_tree **)et->opd2;
                    exp_tree_release( (exp_tree *)et->opd1 );
                    for( i = 0; i < (long)et->opd3; ++i )
                        exp_tree_release( el[i] );
                }
                else if( PCT_TYPE(et->opt) == PCT_DOT )
                {
                    exp_tree_release( (exp_tree *)et->opd1 );
                    token_release( (token *)et->opd2 );
                }
                else
                {
                    if( et->opd1 )
                        exp_tree_release( (exp_tree *)et->opd1 );
                    if( et->opd2 )
                        exp_tree_release( (exp_tree *)et->opd2 );
                    if( et->opd3 )
                        exp_tree_release( (exp_tree *)et->opd3 );
                    break;
                }
            }
        }
    }
    return ref;
}

exp_tree *expression( lex_info *lex )
{
    exp_tree *e, *tmp;
    token *tk, *first;
    lex_his *lh, his;

    first = (token*)lt_get( lex->tokens, lex->cur_token);
    // try to find the expression base on previous parsing
    lh= find_parse( first );
    if( lh != NULL )
    {
        lex->cur_token = lh->until;
        return lh->e;
    }

    e = exp_assign( lex );
    tk = (token *)lt_get( lex->tokens, lex->cur_token );
    while( e && PCT_TYPE(tk) == PCT_COMMA )
    {
        ++lex->cur_token;
        tmp = exp_assign( lex );
        if( tmp )
        {
            e = exp_tree_create( tmp->ret, tk, e, tmp, NULL );
            tk = (token *)lt_get( lex->tokens, lex->cur_token );
        }
        else
        {
            --lex->cur_token;
            break;
        }
    }

    his.e = e;
    his.until = lex->cur_token;
    add_parse( first, &his );
    return e;
}

exp_tree *exp_const( lex_info *lex )
{
    exp_tree *e;
    token *first;
    lex_his *lh, his;
    first = (token*)lt_get( lex->tokens, lex->cur_token);
    // try to find the expression base on previous parsing
    lh= find_parse( first );
    if( lh != NULL )
    {
        lex->cur_token = lh->until;
        return lh->e;
    }
    
    e = exp_cond( lex );
    
    his.e = e;
    his.until = lex->cur_token;
    add_parse( first, &his );
    return e;
}

int is_assign_opt( int opt )
{
    return opt == PCT_ASSIGN         || opt == PCT_ASSIGN_ADD ||
           opt == PCT_ASSIGN_AND     || opt == PCT_ASSIGN_DEV ||
           opt == PCT_ASSIGN_MOD     || opt == PCT_ASSIGN_MUL ||
           opt == PCT_ASSIGN_SHIFT_L || opt == PCT_ASSIGN_SHIFT_R ||
           opt == PCT_ASSIGN_SUB     || opt == PCT_ASSIGN_XOR ||
           opt == PCT_ASSIGN_OR;
}

exp_tree *exp_assign( lex_info *lex )
{
    exp_tree *e, *tmp;
    token *tk;
    int first;
    first = lex->cur_token;
    e = exp_unary( lex );
    tk = (token *)lt_get( lex->tokens, lex->cur_token );
    if( e )
    {
        if( is_assign_opt( PCT_TYPE(tk) ) )
        {
            ++lex->cur_token;
            tmp = exp_assign( lex );
            if( tmp )
            {
                exp_tree *r = exp_tree_create( e->ret, tk, e, tmp, NULL );
                exp_tree_release( e );
                exp_tree_release( tmp );
                return r;
            }
        }
        exp_tree_release( e );
        lex->cur_token = first;
    }
    e = exp_cond( lex );
    return e;
}

exp_tree *exp_cond( lex_info *lex )
{
    exp_tree *e, *tmp1 = NULL, *tmp2 = NULL;
    token *tk;
    int rec_pos;
    e = exp_log_or( lex );
    tk = (token *)lt_get( lex->tokens, lex->cur_token );
    if( e && PCT_TYPE(tk) == PCT_CONDITION )
    {
        rec_pos = lex->cur_token;
        ++lex->cur_token;
        tmp1 = expression( lex );
        tk = (token *)lt_get( lex->tokens, lex->cur_token );
        if( tmp1 && PCT_TYPE(tk) == PCT_CONDITION )
        {
            ++lex->cur_token;
            tmp2 = exp_cond( lex );
            if( tmp2 )
            {
                exp_tree *r = exp_tree_create( tmp1->ret, tk, e, tmp1, tmp2 );
                exp_tree_release( e );
                exp_tree_release( tmp1 );
                exp_tree_release( tmp2 );
                return r;
            }
        }
        if( tmp1 )
        {
            exp_tree_release( tmp1 );
            lex->cur_token = rec_pos;
        }
    }
    return e;
}

exp_tree *exp_log_or( lex_info *lex )
{
    exp_tree *e, *tmp;
    token *tk;
    e = exp_log_and( lex );
    tk = (token *)lt_get( lex->tokens, lex->cur_token );
    while( e && PCT_TYPE(tk) == PCT_LOGICAL_OR )
    {
        ++lex->cur_token;
        tmp = exp_log_and( lex );
        if( tmp )
        {
            exp_tree *r = exp_tree_create( vt_find( "int" ), tk, e, tmp, NULL );
            exp_tree_release( e );
            exp_tree_release( tmp );
            e = r;
            tk = (token *)lt_get( lex->tokens, lex->cur_token );
        }
        else
        {
            --lex->cur_token;
            break;
        }
    }
    return e;
}

exp_tree *exp_log_and( lex_info *lex )
{
    exp_tree *e, *tmp;
    token *tk;
    e = exp_inc_or( lex );
    tk = (token *)lt_get( lex->tokens, lex->cur_token );
    while( e && PCT_TYPE(tk) == PCT_LOGICAL_AND )
    {
        ++lex->cur_token;
        tmp = exp_inc_or( lex );
        if( tmp )
        {
            exp_tree *r = exp_tree_create( vt_find( "int" ), tk, e, tmp, NULL );
            exp_tree_release( e );
            exp_tree_release( tmp );
            e = r;
            tk = (token *)lt_get( lex->tokens, lex->cur_token );
        }
        else
        {
            --lex->cur_token;
            break;
        }
    }
    return e;
}

exp_tree *exp_inc_or( lex_info *lex )
{
    exp_tree *e, *tmp;
    token *tk;
    e = exp_exc_or( lex );
    tk = (token *)lt_get( lex->tokens, lex->cur_token );
    while( e && PCT_TYPE(tk) == PCT_INCLUSIVE_OR )
    {
        ++lex->cur_token;
        tmp = exp_exc_or( lex );
        if( tmp )
        {
            exp_tree *r = exp_tree_create( e->ret, tk, e, tmp, NULL );
            exp_tree_release( e );
            exp_tree_release( tmp );
            e = r;
            tk = (token *)lt_get( lex->tokens, lex->cur_token );
        }
        else
        {
            --lex->cur_token;
            break;
        }
    }
    return e;
}

exp_tree *exp_exc_or( lex_info *lex )
{
    exp_tree *e, *tmp;
    token *tk;
    e = exp_and( lex );
    tk = (token *)lt_get( lex->tokens, lex->cur_token );
    while( e && PCT_TYPE(tk) == PCT_EXCLUSIVE_OR )
    {
        ++lex->cur_token;
        tmp = exp_and( lex );
        if( tmp )
        {
            exp_tree *r = exp_tree_create( e->ret, tk, e, tmp, NULL );
            exp_tree_release( e );
            exp_tree_release( tmp );
            e = r;
            tk = (token *)lt_get( lex->tokens, lex->cur_token );
        }
        else
        {
            --lex->cur_token;
            break;
        }
    }
    return e;
}

exp_tree *exp_and( lex_info *lex )
{
    exp_tree *e, *tmp;
    token *tk;
    e = exp_equal( lex );
    tk = (token *)lt_get( lex->tokens, lex->cur_token );
    while( e && PCT_TYPE(tk) == PCT_AND )
    {
        ++lex->cur_token;
        tmp = exp_equal( lex );
        if( tmp )
        {
            exp_tree *r = exp_tree_create( e->ret, tk, e, tmp, NULL );
            exp_tree_release( e );
            exp_tree_release( tmp );
            e = r;
            tk = (token *)lt_get( lex->tokens, lex->cur_token );
        }
        else
        {
            --lex->cur_token;
            break;
        }
    }
    return e;

}

exp_tree *exp_equal( lex_info *lex )
{
    exp_tree *e, *tmp;
    token *tk;
    e = exp_relat( lex );
    tk = (token *)lt_get( lex->tokens, lex->cur_token );
    while( e && (PCT_TYPE(tk) == PCT_EQUAL || PCT_TYPE(tk) == PCT_UNEQUAL) )
    {
        ++lex->cur_token;
        tmp = exp_relat( lex );
        if( tmp )
        {
            exp_tree *r = exp_tree_create( vt_find( "int" ), tk, e, tmp, NULL );
            exp_tree_release( e );
            exp_tree_release( tmp );
            e = r;
            tk = (token *)lt_get( lex->tokens, lex->cur_token );
        }
        else
        {
            --lex->cur_token;
            break;
        }
    }
    return e;
}

exp_tree *exp_relat( lex_info *lex )
{
    exp_tree *e, *tmp;
    token *tk;
    e = exp_shift( lex );
    tk = (token *)lt_get( lex->tokens, lex->cur_token );
    while( e && (PCT_TYPE(tk) == PCT_LARGE || PCT_TYPE(tk) == PCT_LARGE_EQUAL ||
        PCT_TYPE(tk) == PCT_SMALL || PCT_TYPE(tk) == PCT_SMALL_EQUAL) )
    {
        ++lex->cur_token;
        tmp = exp_shift( lex );
        if( tmp )
        {
            exp_tree *r = exp_tree_create( vt_find( "int" ), tk, e, tmp, NULL );
            exp_tree_release( e );
            exp_tree_release( tmp );
            e = r;
            tk = (token *)lt_get( lex->tokens, lex->cur_token );
        }
        else
        {
            --lex->cur_token;
            break;
        }
    }
    return e;
}

exp_tree *exp_shift( lex_info *lex )
{
    exp_tree *e, *tmp;
    token *tk;
    e = exp_add( lex );
    tk = (token *)lt_get( lex->tokens, lex->cur_token );
    while( e && (PCT_TYPE(tk) == PCT_SHIFT_L || PCT_TYPE(tk) == PCT_SHIFT_R) )
    {
        ++lex->cur_token;
        tmp = exp_add( lex );
        if( tmp )
        {
            exp_tree *r = exp_tree_create( e->ret, tk, e, tmp, NULL );
            exp_tree_release( e );
            exp_tree_release( tmp );
            e = r;
            tk = (token *)lt_get( lex->tokens, lex->cur_token );
        }
        else
        {
            --lex->cur_token;
            break;
        }
    }
    return e;
}

exp_tree *exp_add( lex_info *lex )
{
    exp_tree *e, *tmp;
    token *tk;
    e = exp_mul( lex );
    tk = (token *)lt_get( lex->tokens, lex->cur_token );
    while( e && (PCT_TYPE(tk) == PCT_ADD || PCT_TYPE(tk) == PCT_SUB) )
    {
        ++lex->cur_token;
        tmp = exp_mul( lex );
        if( tmp )
        {
            exp_tree *r = exp_tree_create( e->ret, tk, e, tmp, NULL );
            exp_tree_release( e );
            exp_tree_release( tmp );
            e = r;
            tk = (token *)lt_get( lex->tokens, lex->cur_token );
        }
        else
        {
            --lex->cur_token;
            break;
        }
    }
    return e;
}

exp_tree *exp_mul( lex_info *lex )
{
    exp_tree *e, *tmp;
    token *tk;
    e = exp_cast( lex );
    tk = (token *)lt_get( lex->tokens, lex->cur_token );
    while( e && (PCT_TYPE(tk) == PCT_MUL || PCT_TYPE(tk) == PCT_DEV || PCT_TYPE(tk) == PCT_MOD) )
    {
        ++lex->cur_token;
        tmp = exp_cast( lex );
        if( tmp )
        {
            exp_tree *r = exp_tree_create( e->ret, tk, e, tmp, NULL );
            exp_tree_release( e );
            exp_tree_release( tmp );
            e = r;
            tk = (token *)lt_get( lex->tokens, lex->cur_token );
        }
        else
        {
            --lex->cur_token;
            break;
        }
    }
    return e;
}

exp_tree *exp_cast( lex_info *lex )
{
    exp_tree *e;
    vartype *ty;
    token *tk;
    int first = lex->cur_token;
    tk = (token *)lt_get( lex->tokens, lex->cur_token );
    if( PCT_TYPE(tk) == PCT_PARENTHESES_L )
    {
        ++lex->cur_token;
        ty = type_name( lex );
        tk = (token *)lt_get( lex->tokens, lex->cur_token );
        if( ty && PCT_TYPE(tk) == PCT_PARENTHESES_R )
        {
            ++lex->cur_token;
            e = exp_cast( lex );
            if( e )
            {
                exp_tree *r = exp_tree_create( ty, tk, e, NULL, NULL );
                exp_tree_release( e );
                vt_release( ty );
                return r;
            }
        }
        if( ty )
            vt_release( ty );
        lex->cur_token = first;
    }
    e = exp_unary( lex );
    return e;
}

int is_unary_opt( token *tk )
{
    switch( PCT_TYPE(tk) )
    {
    case PCT_AND:   // PCT_ADRESS
    case PCT_MUL:   // PCT_VALUE
    case PCT_ADD:   // PCT_POSITIVE
    case PCT_SUB:   // PCT_NEGATIVE
    case PCT_NOT:
    case PCT_LOGICAL_NOT:
        return 1;
    }
    return 0;
}

exp_tree *exp_unary( lex_info *lex )
{
    exp_tree *e;
    token *tk, *tmp;
    vartype *ty;
    int first = lex->cur_token;

    tk = (token *)lt_get( lex->tokens, lex->cur_token );
    if( PCT_TYPE(tk) == PCT_INC_PRE || PCT_TYPE(tk) == PCT_DEC_PRE )
    {
        ++lex->cur_token;
        e = exp_unary( lex );
        if( e )
        {
            exp_tree *r = exp_tree_create( e->ret, tk, e, NULL, NULL );
            exp_tree_release( e );
            return r;
        }
        goto ERROR_PROC;
    }
    else if( PCT_TYPE(tk) == PCT_SIZEOF )
    {
        ++lex->cur_token;
        tmp = (token *)lt_get( lex->tokens, lex->cur_token );
        if( PCT_TYPE(tmp) == PCT_PARENTHESES_L )
        {
            ++lex->cur_token;
            ty = type_name( lex );
            tmp = (token *)lt_get( lex->tokens, lex->cur_token );
            if( ty && PCT_TYPE(tmp) == PCT_PARENTHESES_R )
            {
                exp_tree *r;
                ++lex->cur_token;
                r = exp_tree_create( vt_find( "int" ), tk, ty, NULL, NULL );
                vt_release( ty );
                return r;
            }
            if( ty )
                vt_release( ty );
            goto ERROR_PROC;
        }
        else
        {
            e = exp_unary( lex );
            if( e )
            {
                exp_tree *r = exp_tree_create( vt_find( "int" ), tk, e, (void*)1, NULL );
                exp_tree_release( e );
                return r;
            }
            goto ERROR_PROC;
        }
    }
    else if( TOKEN_TYPE(tk) == OPERATOR )
    {
        switch( PCT_TYPE(tk) )
        {
        case PCT_AND:   // PCT_ADRESS
            tk->type = OPERATOR | PCT_ADDRESS;
            ++lex->cur_token;
            e = exp_unary( lex );
            if( e )
            {
                vartype *vt = point_create( e->ret, 0 );
                exp_tree *r = exp_tree_create( vt, tk, e, NULL, NULL );
                exp_tree_release( e );
                return r;
            }
            goto ERROR_PROC;
        case PCT_MUL:   // PCT_VALUE
            tk->type = OPERATOR | PCT_VALUE;
            ++lex->cur_token;
            e = exp_unary( lex );
            if( e && e->ret->type == T_POINT )
            {
                exp_tree *r = exp_tree_create( ((pointtype*)e->ret->name)->base, tk, e, NULL, NULL );
                exp_tree_release( e );
                return r;
            }
            goto ERROR_PROC;
        case PCT_ADD:   // PCT_POSITIVE
            tk->type = OPERATOR | PCT_POSITIVE;
            ++lex->cur_token;
            e = exp_unary( lex );
            if( e )
            {
                exp_tree *r = exp_tree_create( e->ret, tk, e, NULL, NULL );
                exp_tree_release( e );
                return r;
            }
            goto ERROR_PROC;
        case PCT_SUB:   // PCT_NEGATIVE
            tk->type = OPERATOR | PCT_NEGATIVE;
            ++lex->cur_token;
            e = exp_unary( lex );
            if( e )
            {
                exp_tree *r = exp_tree_create( e->ret, tk, e, NULL, NULL );
                exp_tree_release( e );
                return r;
            }
            goto ERROR_PROC;
        case PCT_NOT:
        case PCT_LOGICAL_NOT:
            ++lex->cur_token;
            e = exp_unary( lex );
            if( e )
            {
                exp_tree *r = exp_tree_create( e->ret, tk, e, NULL, NULL );
                exp_tree_release( e );
                return r;
            }
            goto ERROR_PROC;
        default:
            break;
        }
    }
    e = exp_post( lex );
    return e;

ERROR_PROC:
    lex->cur_token = first;
    return NULL;
}

exp_tree *exp_post( lex_info *lex )
{
    exp_tree *el[MAX_NR_FUNC_PARA];
    int nr_el;
    exp_tree *e, *tmp;
    token *tk, *t;
    vartype *ty;
    int first = lex->cur_token;

    tk = (token *)lt_get( lex->tokens, lex->cur_token );
    if( PCT_TYPE(tk) == PCT_PARENTHESES_L )
    {
        ++lex->cur_token;
        ty = type_name( lex );
        tk = (token *)lt_get( lex->tokens, lex->cur_token );
        if( ty && PCT_TYPE(tk) == PCT_PARENTHESES_R )
        {
            // TODO:
        }
    }
    e = exp_primary( lex );
    while( e )
    {
        first = lex->cur_token;
        tk = (token *)lt_get( lex->tokens, lex->cur_token );
        switch( PCT_TYPE(tk) )
        {
        case PCT_ARRAY_L:
            ++lex->cur_token;
            tmp = expression( lex );
            tk = (token *)lt_get( lex->tokens, lex->cur_token );
            if( tmp && PCT_TYPE(tk) == PCT_ARRAY_R )
            {
                exp_tree *r;
                vartype *vt = array_create( e->ret, tmp, 0 );
                r = exp_tree_create( vt, tk, e, tmp, NULL );
                exp_tree_release( e );
                exp_tree_release( tmp );
                e = r;
                ++lex->cur_token;
                continue;
            }
            else if( tmp )
            {
                // miss "]"
                exp_tree_release( tmp );
                lex->cur_token = first;
            }
            break;
        case PCT_PARENTHESES_L:
            nr_el = 0;
            ++lex->cur_token;
            el[nr_el++] = exp_assign( lex );
            while( el[nr_el-1] )
            {
                tk = (token *)lt_get( lex->tokens, lex->cur_token );
                if( PCT_TYPE(tk) == PCT_COMMA )
                {
                    ++lex->cur_token;
                    el[nr_el++] = exp_assign( lex );
                }
                else
                    break;
            }
            if( el[nr_el-1] == NULL )
                --nr_el;
            if( PCT_TYPE(tk) == PCT_PARENTHESES_R )
            {
                exp_tree **para, *r;
                int i;
                tk->type = OPERATOR | PCT_CALL;
                para = (exp_tree **)malloc( sizeof(exp_tree*) * nr_el );
                memcpy( para, el, sizeof(exp_tree*) * nr_el );
                r = exp_tree_create( e->ret, tk, e, para, (void*)nr_el );
                exp_tree_release( e );
                for( i = 0; i < nr_el; ++i )
                    exp_tree_release( el[i] );
                e = r;
                continue;
            }
            else
            {
                int i;
                for( i = 0; i < nr_el; ++i )
                    exp_tree_release( el[i] );
                lex->cur_token = first;
            }
            break;
        case PCT_DOT:
            ++lex->cur_token;
            t = (token *)lt_get( lex->tokens, lex->cur_token );
            if( TOKEN_TYPE(t) == IDENTIFIER )
            {
                exp_tree *r;
                vartype *vt = NULL, *tmp;
                tmp = e->ret;
                if( tmp->type == T_SIMPLE )
                {
                    symbol *sym = (symbol *)tmp->name;
                    symtype *st = sym->type;
                    structtype *stt;
                    uniontype *ut;
                    int i;
                    switch( st->syn )
                    {
                    case T_STRUCT:
                        stt = (structtype *)st->attr;
                        for( i = 0; i < lt_size( stt->member ); ++i )
                        {
                            structmem *sm = (structmem*)lt_get( stt->member, i);
                            if( 0 == tkcmp( t, sm->name ) )
                            {
                                vt = sm->type;
                                break;
                            }
                        }
                        if( vt )
                        {
                            r = exp_tree_create( vt, tk, e, t, NULL );
                            ++lex->cur_token;
                            continue;
                        }
                        break;
                    case T_UNION:
                        ut = (uniontype *)st->attr;
                        for( i = 0; i < lt_size( ut->member ); ++i )
                        {
                            structmem *sm = (structmem*)lt_get( ut->member, i );
                            if( 0 == tkcmp( t, sm->name ) )
                            {
                                vt = sm->type;
                                break;
                            }
                        }
                        if( vt )
                        {
                            r = exp_tree_create( vt, tk, e, t, NULL );
                            ++lex->cur_token;
                            continue;
                        }
                        break;
                    }
                }
            }
            lex->cur_token = first;
            break;
        case PCT_POINT:
            ++lex->cur_token;
            t = (token *)lt_get( lex->tokens, lex->cur_token );
            if( TOKEN_TYPE(t) == IDENTIFIER )
            {
                exp_tree *r;
                vartype *vt = NULL, *tmp;
                tmp = e->ret;
                if( tmp->type == T_POINT )
                {
                    symbol *sym = (symbol *)((pointtype *)tmp->name)->base->name;
                    symtype *st = sym->type;
                    structtype *stt;
                    uniontype *ut;
                    int i;
                    switch( st->syn )
                    {
                    case T_STRUCT:
                        stt = (structtype *)st->attr;
                        for( i = 0; i < lt_size( stt->member ); ++i )
                        {
                            structmem *sm = (structmem*)lt_get( stt->member, i);
                            if( 0 == tkcmp( t, sm->name ) )
                            {
                                vt = sm->type;
                                break;
                            }
                        }
                        if( vt )
                        {
                            r = exp_tree_create( vt, tk, e, t, NULL );
                            ++lex->cur_token;
                            continue;
                        }
                        break;
                    case T_UNION:
                        ut = (uniontype *)st->attr;
                        for( i = 0; i < lt_size( ut->member ); ++i )
                        {
                            structmem *sm = (structmem*)lt_get( ut->member, i );
                            if( 0 == tkcmp( t, sm->name ) )
                            {
                                vt = sm->type;
                                break;
                            }
                        }
                        if( vt )
                        {
                            r = exp_tree_create( vt, tk, e, t, NULL );
                            ++lex->cur_token;
                            continue;
                        }
                        break;
                    }
                }
            }
            lex->cur_token = first;
            break;
        case PCT_INC_PRE:
            tk->type = OPERATOR | PCT_INC_POST;
            e = exp_tree_create( e->ret, tk, e, NULL, NULL );
            ++lex->cur_token;
            continue;
            break;
        case PCT_DEC_PRE:
            tk->type = OPERATOR | PCT_DEC_POST;
            e = exp_tree_create( e->ret, tk, e, NULL, NULL );
            ++lex->cur_token;
            continue;
            break;
        }
        break;
    }
    return e;
}

exp_tree *exp_primary( lex_info *lex )
{
    exp_tree *e = NULL;
    token *tk;
    tk = (token *)lt_get( lex->tokens, lex->cur_token );
    if( PCT_TYPE(tk) == PCT_PARENTHESES_L )
    {
        ++lex->cur_token;
        e = expression( lex );
        tk = (token *)lt_get( lex->tokens, lex->cur_token );
        if( e == NULL )
            --lex->cur_token;
        if( PCT_TYPE(tk) == PCT_PARENTHESES_R )
            ++lex->cur_token;
    }
    else
    {
        vartype *vt, *t;
        symbol *sym;
        switch( TOKEN_TYPE(tk) )
        {
        case IDENTIFIER:
            sym = sym_find( tk->name );
            if( sym )
            {
                symtype *st = sym->type;
                switch( st->syn )
                {
                case T_VAR:
                    e = exp_tree_create( (vartype *)st->attr, NULL, tk, NULL, NULL );
                    break;
                case T_FUNC:
                    e = exp_tree_create( ((functype *)st->attr)->ret, NULL, tk, NULL, NULL );
                    break;
                }
            }
            sym_release( sym );
            break;
        case CHARACTER:
            vt = vt_find( "char" );
            e = exp_tree_create( vt, NULL, tk, NULL, NULL );
            vt_release( vt );
            break;
        case STRING:
            vt = vt_find( "char" );
            t = point_create( vt, 0 );
            e = exp_tree_create( t, NULL, tk, NULL, NULL );
            vt_release( vt );
            vt_release( t );
            break;
        case INTEGER:
            vt = vt_find( "int" );
            e = exp_tree_create( vt, NULL, tk, NULL, NULL );
            vt_release( vt );
            break;
        case FLOATING:
            vt = vt_find( "float" );
            e = exp_tree_create( vt, NULL, tk, NULL, NULL );
            vt_release( vt );
            break;
        }
    }
    return e;
}
